#include "sccamera.h"

SCCamera::SCCamera(QString cameraName, CameraConfig *cameraConfig, QObject *parent)
    : QThread(parent), QQuickImageProvider(QQuickImageProvider::Image), m_cameraName(cameraName), m_config(cameraConfig)
{
    setHasSecondLightSourceChannel(cameraConfig->secondLightSourceChannel() >= 0);
    connect(cameraConfig, &CameraConfig::secondLightSourceChannelChanged, this,
            &SCCamera::onSecondLightSourceChannelChanged);
}

SCCamera::~SCCamera() {}

void SCCamera::setLsc(LightSourceController *lsc)
{
    this->lsc = lsc;
}

void SCCamera::setTwoChanndelBrightness(int brightness1, int brightness2, bool waitStable)
{
    if (lsc == nullptr)
    {
        throw SilicolAbort(tr("Light source controller was not set! Camera: %1, LSC name: %2")
                               .arg(m_cameraName)
                               .arg(m_config->lscName()),
                           EX_LOCATION);
    }

    bool anyBrightnessChanged = false;
    if (m_lightSourceBrightness != brightness1)
    {
        try
        {
            lsc->setBrightness(m_config->lightSourceChannel(), brightness1);
        }
        catch (SilicoolException &se)
        {
            emit lightSourceBrightnessChanged(m_lightSourceBrightness);
            throw se;
        }

        m_lightSourceBrightness = brightness1;
        emit lightSourceBrightnessChanged(m_lightSourceBrightness);
        anyBrightnessChanged = true;
    }

    if (hasSecondLightSourceChannel() && m_secondLightSourceBrightness != brightness2)
    {
        try
        {
            lsc->setBrightness(m_config->secondLightSourceChannel(), brightness2);
        }
        catch (SilicoolException &se)
        {
            emit lightSourceBrightnessChanged(m_secondLightSourceBrightness);
            throw se;
        }

        m_secondLightSourceBrightness = brightness2;
        emit secondLightSourceBrightnessChanged(m_secondLightSourceBrightness);
        anyBrightnessChanged = true;
    }

    if (anyBrightnessChanged && waitStable && m_config->delayAfterChangeBrightness() > 0)
    {
        QThread::msleep(m_config->delayAfterChangeBrightness());
    }
}

void SCCamera::startShowRealtimeImage(bool useIntervalFromConfig)
{
    if (isShowRealtimeImage())
    {
        return;
    }
    this->useIntervalFromConfig = useIntervalFromConfig;
    setIsShowRealtimeImage(true);
    start();
}

void SCCamera::stopShowRealtimeImage()
{
    if (isShowRealtimeImage())
    {
        setIsShowRealtimeImage(false);
        wait();
    }
}

QImage SCCamera::getImage(bool showThisImage, bool saveThisImage)
{
    if (!isOpened())
    {
        throw GeneralError("Vision", tr("Camera %1 is not opened!").arg(cameraName()));
    }

    QImage img;
    {
        QMutexLocker tmpLocker(&locker);
        img = getImageImpl();
    }

    if (config()->horizontalMirror() || config()->verticalMirror())
    {
        img = img.mirrored(config()->horizontalMirror(), config()->verticalMirror());
    }
    if (showThisImage)
    {
        showImage(img);
    }
    if (saveThisImage)
    {
        saveImage(img);
    }
    return img;
}

void SCCamera::showImage(QImage &image)
{
    lastImage = image;
    emit imageChanged();
}

void SCCamera::saveImage(QString dir, QString name)
{
    QImage image;
    if (isShowRealtimeImage() && m_config->showRealTimeImageInterval() < 150)
    {
        image = lastImage.copy();
    }
    else
    {
        image = getImage(true, false);
    }
    saveImage(image, dir, name);
}

void SCCamera::saveImage(QImage image, QString dir, QString name)
{
    if (dir.isEmpty())
    {
        dir = QString("./images/%1/%2/").arg(QDateTime::currentDateTime().toString("yyyy_MM_dd")).arg(m_cameraName);
    }

    if (name.isEmpty())
    {
        name = QString("%1_%2.jpg").arg(m_cameraName).arg(QDateTime::currentDateTime().toString("hh_mm_ss_zzz"));
    }

    ImageSaver::getIns().saveImage(image, dir, name);
}

void SCCamera::setLightSourceBrightness(int lightSourceBrightness)
{
    if (m_lightSourceBrightness == lightSourceBrightness)
        return;

    if (lsc == nullptr)
    {
        throw SilicolAbort(tr("Light source controller was not set! Camera: %1, LSC name: %2")
                               .arg(m_cameraName)
                               .arg(m_config->lscName()),
                           EX_LOCATION);
    }
    try
    {
        lsc->setBrightness(m_config->lightSourceChannel(), lightSourceBrightness);
    }
    catch (SilicoolException &se)
    {
        emit lightSourceBrightnessChanged(m_lightSourceBrightness);
        throw se;
    }

    m_lightSourceBrightness = lightSourceBrightness;
    emit lightSourceBrightnessChanged(m_lightSourceBrightness);
}

void SCCamera::setSecondLightSourceBrightness(int secondLightSourceBrightness)
{
    if (m_secondLightSourceBrightness == secondLightSourceBrightness)
        return;
    if (!hasSecondLightSourceChannel())
        return;

    if (lsc == nullptr)
    {
        throw SilicolAbort(tr("Light source controller was not set! Camera: %1, LSC name: %2")
                               .arg(m_cameraName)
                               .arg(m_config->lscName()),
                           EX_LOCATION);
    }
    try
    {
        lsc->setBrightness(m_config->secondLightSourceChannel(), secondLightSourceBrightness);
    }
    catch (SilicoolException &se)
    {
        emit lightSourceBrightnessChanged(m_secondLightSourceBrightness);
        throw se;
    }

    m_secondLightSourceBrightness = secondLightSourceBrightness;
    emit secondLightSourceBrightnessChanged(m_secondLightSourceBrightness);
}

void SCCamera::run()
{
    try
    {
        while (isShowRealtimeImage())
        {
            getImage(true, false);
            QElapsedTimer timer;
            timer.start();
            int interval = useIntervalFromConfig ? m_config->showRealTimeImageInterval() : 100;
            while (timer.elapsed() < interval && isShowRealtimeImage())
            {
                QThread::msleep(20);
            }
        }
    }
    catch (SilicoolException &se)
    {
        qCCritical(visionCate()) << se.what();
    }
    setIsShowRealtimeImage(false);
}

QImage SCCamera::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
    Q_UNUSED(id)
    Q_UNUSED(size)
    Q_UNUSED(requestedSize)
    return lastImage;
}
